package com.bigdata;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

/**
 * 海量日志数据提取出某日访问百度次数最多的IP
 * 
 * ip 地址最多有2^32=4G，所以全部加载在内容中是不现实的
 * 
 * 可以考虑“分而治之”--使用hash(ip) % 1024，将ip分配到1024个小文件中，这样每个文件就只有4M个ip地址
 * 
 * 对于每个小文件，使用hashMap，其key为ip，value为出现的次数。最会对1024个hashmap求最大值即可
 * 
 * @author lihhz
 *
 */
public class LogCount {

	private static String PATH = "D:\\test\\ip.txt";

	private static void getMax() throws IOException {

		Calendar cal = Calendar.getInstance();
		Date begin = cal.getTime();
		System.out.println(begin);
//		System.out.println("开始划分数据..");
//		splitFile();
//		System.out.println("数据划分完毕！");

		String filePath = "D:\\test\\big";
		File file = new File(filePath);
		if (file.exists()) {
			Map<String, Long> resultMap = new HashMap<String, Long>();
			File[] fs = file.listFiles();

			for (File f : fs) {
				// if(f.isDirectory() || f.getName().contains("ip.txt")){
				// continue;
				// }
				Map<String, Long> map = new HashMap<String, Long>();
				try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f)));) {
					String line = null;
					while ((line = reader.readLine()) != null) {
						map.put(line, (map.containsKey(line) ? map.get(line) : 0) + 1);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				String ip = null;
				long count = -1;
				Iterator<Entry<String, Long>> it = map.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<String, Long> entry = it.next();
					Long l = entry.getValue();
					if (l > count) {
						ip = entry.getKey();
						count = entry.getValue();
					}
				}
				resultMap.put(ip, count);

			}
			String ip = null;
			long count = -1;
			Iterator<Entry<String, Long>> it = resultMap.entrySet().iterator();
			while (it.hasNext()) {
				Map.Entry<String, Long> entry = it.next();
				Long l = entry.getValue();
				if (l > count) {
					ip = entry.getKey();
					count = entry.getValue();
				}
			}

			System.out.println(ip + " 出现次数最多：" + count);
			
			cal = Calendar.getInstance();
			Date end = cal.getTime();
			System.out.println(end);
			System.out.println("耗时：" + (end.getTime() - begin.getTime()));
		}
	}

	/**
	 * 将大文件按照Hash(ip)%1024进行划分
	 * 
	 * @throws IOException
	 */
	private static void splitFile() throws IOException {

		try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(PATH))));) {
			String line = null;
			while ((line = reader.readLine()) != null) {
				String filePath = "D:\\test\\big\\" + (getHash(line) % 512) + ".txt";
				File file = new File(filePath);
				if (!file.exists()) {
					file.createNewFile();
				}

				AppendFile.method2(filePath, line + "\n");
			}
		}
	}

	// 获取HashCode
	private static int getHash(String ip) {
		return ip.hashCode();
	}

	public static void main(String[] args) throws IOException {
//		getMax();
		System.out.println(getHash("61.237.99.99")%512);
		// try {
		// IpHelper.writeFile();
		// } catch (IOException e) {
		// e.printStackTrace();
		// }
	}

	/**
	 * 测试辅助类
	 * 
	 * @author lihhz
	 *
	 */
	@SuppressWarnings("unused")
	private static class IpHelper {

		private static String PATH = "D:\\test\\ip.txt";

		// 向文件中插入尽可能多的ip
		private static void writeFile() throws IOException {
			File file = new File(PATH);
			if (!file.exists()) {
				file.createNewFile();
			}

			BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true)));

			for (long i = 0; i < Integer.MAX_VALUE / 20; i++) {// 10
				out.write(getRandomIp() + "\n");
			}

			out.flush();
			out.close();
		}
//		Java随机生成批量Ip
		private static String getRandomIp() {
			// ip范围
			int[][] range = { { 607649792, 608174079 }, // 36.56.0.0-36.63.255.255
					{ 1038614528, 1039007743 }, // 61.232.0.0-61.237.255.255
					{ 1783627776, 1784676351 }, // 106.80.0.0-106.95.255.255
					{ 2035023872, 2035154943 }, // 121.76.0.0-121.77.255.255
					{ 2078801920, 2079064063 }, // 123.232.0.0-123.235.255.255
					{ -1950089216, -1948778497 }, // 139.196.0.0-139.215.255.255
					{ -1425539072, -1425014785 }, // 171.8.0.0-171.15.255.255
					{ -1236271104, -1235419137 }, // 182.80.0.0-182.92.255.255
					{ -770113536, -768606209 }, // 210.25.0.0-210.47.255.255
					{ -569376768, -564133889 }, // 222.16.0.0-222.95.255.255
			};

			int index = new Random().nextInt(10);
			// 返回ip
			return num2ip(range[index][0] + new Random().nextInt(range[index][1] - range[index][0]));
		}

		/*
		 * 将十进制转换成IP地址
		 */
		private static String num2ip(int ip) {
			int[] b = new int[4];
			b[0] = (int) ((ip >> 24) & 0xff);
			b[1] = (int) ((ip >> 16) & 0xff);
			b[2] = (int) ((ip >> 8) & 0xff);
			b[3] = (int) (ip & 0xff);

			// 返回ip地址
			return Integer.toString(b[0]) + "." + Integer.toString(b[1]) + "." + Integer.toString(b[2]) + "."
					+ Integer.toString(b[3]);

		}

	}

	/**
	 * 向文件中追加内容
	 * 
	 * @author malik
	 * @version 2011-3-10 下午10:49:41
	 */
	static class AppendFile {

		// 频繁new、close影响性能，这里的hashcode已经固定了，所以这样使用
		static Map<String, BufferedWriter> bufferedWriterMap = new HashMap<String, BufferedWriter>(1024);
		static Map<String, FileWriter> fileWriterMap = new HashMap<String, FileWriter>(1024);
		static Map<String, RandomAccessFile> randomAccessFileMap = new HashMap<String, RandomAccessFile>(1024);

		public static void method1(String file, String conent) throws IOException {
			BufferedWriter out = null;
			if (bufferedWriterMap.containsKey(file)) {
				out = bufferedWriterMap.get(file);
			} else {
				out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true)));
				bufferedWriterMap.put(file, out);
			}
			out.write(conent);
		}

		/**
		 * 追加文件：使用FileWriter
		 * 
		 * @param fileName
		 * @param content
		 * @throws IOException
		 */
		public static void method2(String fileName, String content) throws IOException {
			FileWriter writer = null;
			if (fileWriterMap.containsKey(fileName)) {
				writer = fileWriterMap.get(fileName);
			} else {
				writer = new FileWriter(fileName, true);
				fileWriterMap.put(fileName, writer);
			}
			writer.write(content);
		}

		/**
		 * 追加文件：使用RandomAccessFile
		 * 
		 * @param fileName
		 *            文件名
		 * @param content
		 *            追加的内容
		 * @throws IOException
		 */
		public static void method3(String fileName, String content) throws IOException {
			RandomAccessFile randomFile = null;
			if (randomAccessFileMap.containsKey(fileName)) {
				randomFile = randomAccessFileMap.get(fileName);
			} else {
				randomFile = new RandomAccessFile(fileName, "rw");
				randomAccessFileMap.put(fileName, randomFile);
			}
			// 文件长度，字节数
			long fileLength = randomFile.length();
			// 将写文件指针移到文件尾。
			randomFile.seek(fileLength);
			randomFile.writeBytes(content);
		}

		// public static void main(String[] args) {
		// try {
		// File file = new File("d://text.txt");
		// if (file.createNewFile()) {
		// System.out.println("Create file successed");
		// }
		// method1("d://text.txt", "123");
		// method2("d://text.txt", "123");
		// method3("d://text.txt", "123");
		// } catch (Exception e) {
		// System.out.println(e);
		// }
		// }
	}
}
